#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>

#define DEBUG 1
#include <include/pf_json.h>

#define is_error(ptr) (ptr == NULL)

int json_print(void* arg, char *key, struct pf_json_object* val)
{
    printf("print: arg = %s , key = %s , val = %s \n", (char*)arg, key , pf_json_obj_to_json_str(val));
    return 0;
}

int main()
{
  pf_json_tokener_t *tok;
  pf_json_object_t *my_string, *my_int, *my_object, *my_array;
  pf_json_object_t *new_obj;
  int i;
  enum pf_json_tokener_error error;


  PF_JSON_SET_DEBUG(1);

  my_string = pf_json_create_str_obj("\t");
  printf("my_string=%s\n", pf_json_get_str(my_string));
  printf("my_string.to_string()=%s\n", pf_json_obj_to_json_str(my_string));
  pf_json_put_obj(my_string);

  my_string = pf_json_create_str_obj("\\");
  printf("my_string=%s\n", pf_json_get_str(my_string));
  printf("my_string.to_string()=%s\n", pf_json_obj_to_json_str(my_string));
  pf_json_put_obj(my_string);

  my_string = pf_json_create_str_obj("foo");
  printf("my_string=%s\n", pf_json_get_str(my_string));
  printf("my_string.to_string()=%s\n", pf_json_obj_to_json_str(my_string));

  my_int = pf_json_create_int_obj(9);
  printf("my_int=%d\n", pf_json_get_int(my_int));
  printf("my_int.to_string()=%s\n", pf_json_obj_to_json_str(my_int));

  my_array = pf_json_create_array_obj();
  pf_json_array_obj_add_item(my_array, pf_json_create_int_obj(1));
  pf_json_array_obj_add_item(my_array, pf_json_create_int_obj(2));
  pf_json_array_obj_add_item(my_array, pf_json_create_int_obj(3));
  pf_json_array_obj_put_item(my_array, 4, pf_json_create_int_obj(5));
  printf("my_array=\n");
  for(i=0; i < pf_json_array_obj_len(my_array); i++) {
    pf_json_object_t *obj = pf_json_array_obj_get_item(my_array, i);
    printf("\t[%d]=%s\n", i, pf_json_obj_to_json_str(obj));
  }
  printf("my_array.to_string()=%s\n", pf_json_obj_to_json_str(my_array));    

  my_object = pf_json_create_obj();
  pf_json_add_sub_obj(my_object, "abc", pf_json_create_int_obj(12));
  pf_json_add_sub_obj(my_object, "foo", pf_json_create_str_obj("bar"));
  pf_json_add_sub_obj(my_object, "bool0", pf_json_create_bool_obj(0));
  pf_json_add_sub_obj(my_object, "bool1", pf_json_create_bool_obj(1));
  pf_json_add_sub_obj(my_object, "baz", pf_json_create_str_obj("bang"));
  pf_json_add_sub_obj(my_object, "baz", pf_json_create_str_obj("fark"));
  pf_json_del_sub_obj(my_object, "baz");
  pf_json_add_sub_obj(my_object, "arr", my_array);
  printf("my_object=\n");
  pf_json_obj_for_each(my_object, "test foreach", json_print);

  printf("my_object.to_string()=%s\n", pf_json_obj_to_json_str(my_object));

  new_obj = pf_json_parse("\"\003\"");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("/* hello */\"foo\"");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("// hello\n\"foo\"");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("\"\\u0041\\u0042\\u0043\"");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("null");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("True");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("12");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("12.3");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("[\"\\n\"]");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("[\"\\nabc\\n\"]");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("[null]");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("[]");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("[false]");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("[\"abc\",null,\"def\",12]");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("{}");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("{ \"foo\": \"bar\" }");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("{ \"foo\": [null, \"foo\"] }");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  new_obj = pf_json_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }");
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);

  error = PF_JSON_TOK_SUCCESS;
  new_obj = pf_json_parse_verbose("{ foo }", &error);
  assert (error == PF_JSON_TOK_ERR_PARSE_OBJECT_KEY_NAME);
  assert (new_obj == NULL);

  new_obj = pf_json_parse("{ foo }");
  assert (new_obj == NULL);
  
  if(is_error(new_obj)) printf("got error as expected\n");

  new_obj = pf_json_parse("foo");
  assert (new_obj == NULL);
  new_obj = pf_json_parse_verbose("foo", &error);
  assert (new_obj == NULL);
  assert (error == PF_JSON_TOK_ERR_PARSE_BOOLEAN);

  new_obj = pf_json_parse("{ \"foo");
  if(is_error(new_obj)) printf("got error as expected\n");

  /* test incremental parsing */
  tok = pf_json_create_tokener();
  new_obj = pf_json_parse_ex(tok, "{ \"foo", 6);
  if(is_error(new_obj)) printf("got error as expected\n");
  new_obj = pf_json_parse_ex(tok, "\": {\"bar", 8);
  if(is_error(new_obj)) printf("got error as expected\n");
  new_obj = pf_json_parse_ex(tok, "\":13}}", 6);
  printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(new_obj));
  pf_json_put_obj(new_obj);  
  pf_json_destroy_tokener(tok);

  pf_json_put_obj(my_string);
  pf_json_put_obj(my_int);
  pf_json_put_obj(my_object);
  pf_json_put_obj(my_array);

  sleep(5); 

  {
      pf_json_object_t* my_int_aa = pf_json_create_int_obj(9);
      printf("new_obj.to_string()=%s\n", pf_json_obj_to_json_str(my_int_aa));
  }
  printf("exit\n");


  //MC_DEBUG("end \n");

  return 0;
}
